/*
 * Copyright 2008 Carnegie Mellon University
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, 
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package edu.cmu.lti.sepia.servlet;

import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import edu.cmu.lti.sepia.data.db.IRJudgmentUnitDAO;
import edu.cmu.lti.sepia.data.db.PoolDAO;
import edu.cmu.lti.sepia.data.db.QAJudgmentUnitDAO;
import edu.cmu.lti.sepia.data.db.SQL;
import edu.cmu.lti.sepia.data.db.TopicDAO;
import edu.cmu.lti.sepia.infra.eval.model.Pool;
import edu.cmu.lti.sepia.infra.run.RunXmlFacade;
import edu.cmu.lti.sepia.infra.run.model.RetrievalResultSet;
import edu.cmu.lti.sepia.infra.run.model.SelectionResultSet;
import edu.cmu.lti.sepia.infra.topic.model.Topic;
import edu.cmu.lti.sepia.util.ExceptionUtil;
import edu.cmu.lti.sepia.util.Logger;
import edu.cmu.lti.sepia.util.ServletUtil;

public class PoolImporter extends HttpServlet {

  private static final long serialVersionUID = 1L;

  private final static int THRESHOLD = 50*1024*1024;
  private final static long MAXSIZE = 100*1024*1024;
  
  private final static String formAction = "/io/pool_importer.html";

  private final static String POOL_DELETE_SUCCEEDED = "<br><strong style=\"color:#ff0000\">The pool has been successfully deleted.</strong><br>\n";
  private final static String UPLOAD_SUCCEEDED = "<br><strong style=\"color:#ff0000\">Upload succeeded.</strong><br>\n";
  private final static String UPLOAD_SYSTEM_ERROR = "<br><strong style=\"color:#ff0000\">Upload failed. Please report the error message and send the file to the system admin by email.</strong><br>\n";
  
  public void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {

    ServletOutputStream out = response.getOutputStream();
    Commons.printHeader(request, response, "Pool Manager", 2);

    ServletUtil s = new ServletUtil( request );
    String taskNameShort = s.readString("taskNameShort", "");
    
    SQL sql = new SQL();
    try {
      out.println( getUploadForm(request, response, sql, taskNameShort, 
              request.getContextPath()+formAction) );
    } catch (Exception e) {
      throw new IOException(e);
    } finally {
      try {
        sql.close();
      } catch (Exception e){e.printStackTrace();}
    }
    Commons.printFooter(request, response);
  }
  
  public void doPost(HttpServletRequest request, HttpServletResponse response)
	  throws ServletException, IOException {
    ServletOutputStream out = response.getOutputStream();
    Commons.printHeader(request, response, "Pool Manager", 2);
    
    ServletUtil s = new ServletUtil( request );
    String taskNameShort = s.readString("taskNameShort", "");
    String irPoolId = s.readString("ir_pool_delete", "");
    String qaPoolId = s.readString("qa_pool_delete", "");
    
    SQL sql = new SQL();
    try {
      String report;
      if (irPoolId.length()>0 || qaPoolId.length()>0) {
        // action: delete pool
        report = deletePool( request, sql, taskNameShort, irPoolId, qaPoolId );
      } else {
        // action: upload a pool file and create a pool 
        report = upload( request, response, sql, taskNameShort );
      }
      out.println( "<hr>" );
      out.println( report );
      out.println( getUploadForm(request, response, sql, taskNameShort, 
              request.getContextPath()+formAction) );
    } catch (Exception e) {
      throw new IOException(e);
    } finally {
      try {
        sql.close();
      } catch (Exception e){e.printStackTrace();}
    }
    
    Commons.printFooter(request, response);
	}
  
  public String getUploadForm(HttpServletRequest request, HttpServletResponse response, 
          SQL sql, String taskNameShort, String actionPath) 
    throws IOException, SQLException {

    StringBuilder sb = new StringBuilder();
    sb.append("<br><h4>Pool File Uploader</h4>\n");
    sb.append("Enter the pool name (e.g. pd100-50), and specifiy the pool file and then click upload button.<br><br>");    
    sb.append("<form action=\""+actionPath+"\" method=\"POST\" enctype=\"multipart/form-data\" onsubmit=\"if(!$('file').value){alert('Please select the file to upload');return false;};\">\n");    
    sb.append("<table>\n");
    sb.append("<tr><td>Pool Type</td><td>\n");
    sb.append("<input type=\"radio\" name=\"poolType\" id=\"ir_pool\" value=\"ir_pool\" checked><label id=\"ir_help\" for=\"ir_pool\" title=\"IR pool file\">IR</label>&nbsp;&nbsp;\n");
    sb.append("<input type=\"radio\" name=\"poolType\" id=\"qa_pool\" value=\"qa_pool\"><label id=\"qa_help\" for=\"qa_pool\" title=\"QA pool file\">QA</label>\n");
    sb.append("</td></tr>\n");
    sb.append("<tr><td>Pool Name</td><td>\n");
    sb.append("<input type=\"text\" name=\"poolName\" id=\"poolName\" title=\"Name of the pool (e.g. pd100-50.txt)\">\n");
    sb.append("</td></tr>\n");
    sb.append("<tr><td>File</td><td><input type=\"file\" name=\"file\" id=\"file\"></td></tr>\n");
    sb.append("<tr><td colspan=2><input type=\"submit\" value=\" upload \" onclick=\"return verifyNonBlank($('poolName'));\"></td></tr>\n");
    sb.append("</table>");
    sb.append("</form>\n");
    
    sb.append("<br><br><hr>");
    sb.append("<br><h4>Pool Delete Tool</h4>\n");
    sb.append("Delete a pool in case you wrongly created one (this action cannot be undone).<br><br>\n");
    sb.append("<form action=\""+actionPath+"\" method=\"POST\" " +
    		"onsubmit=\"return (jQuery('#ir_pool_delete').val().length>0||jQuery('#qa_pool_delete').val().length>0)&& deleteConfirmed()\">\n");
    sb.append("<table><tr><td>IR Pools</td><td><select id=\"ir_pool_delete\" name=\"ir_pool_delete\">\n");
    sb.append("<option value=\"\">Please select a pool name\n");
    List<Pool> pools = PoolDAO.getPools(sql, taskNameShort, true );
    for ( Pool pool : pools ) {
      sb.append("<option value=\""+pool.getPoolId()+"\">"+pool.getPoolName()+"</option>\n");      
    }
    sb.append("</select></td></tr>\n");
    sb.append("<tr><td>QA Pools</td><td><select id=\"qa_pool_delete\" name=\"qa_pool_delete\">\n");
    sb.append("<option value=\"\">Please select a pool name\n");
    pools = PoolDAO.getPools(sql, taskNameShort, false );
    for ( Pool pool : pools ) {
      sb.append("<option value=\""+pool.getPoolId()+"\">"+pool.getPoolName()+"</option>\n");      
    }
    sb.append("</select></td></tr></table>\n");
    sb.append("<input type=\"submit\" value=\" delete \" ><br><br>\n");
    sb.append("</form>");
    sb.append("<script type=\"text/javascript\">\n");
    sb.append("jQuery(document).ready(function($) {\n");
    sb.append("  $('#poolName,#ir_help,#qa_help').tipsy({gravity:'s'}); });\n");
    sb.append("</script>\n");
    return sb.toString();
  }
  
  public String deletePool(HttpServletRequest request, SQL sql, String taskNameShort,
          String irPoolId, String qaPoolId) {
    try {
      if (irPoolId.length()>0) {
        int poolId = Integer.parseInt(irPoolId);
        PoolDAO.deletePool(sql, taskNameShort, poolId, true);
        Logger.log(sql, request.getSession(), "DELETE IR POOL", "id="+poolId);
      }
      if (qaPoolId.length()>0) {
        int poolId = Integer.parseInt(qaPoolId);
        PoolDAO.deletePool(sql, taskNameShort, poolId, false);
        Logger.log(sql, request.getSession(), "DELETE QA POOL", "id="+poolId);
      }
    } catch (Exception e) {
      return "An error occurred while deleting the pool:<br>"+ExceptionUtil.exceptionToString(e);
    }
    return POOL_DELETE_SUCCEEDED;
  }

  @SuppressWarnings("unchecked")
  public String upload(HttpServletRequest request, HttpServletResponse response, 
          SQL sql, String taskNameShort ) throws ServletException, IOException {

    StringBuilder report = new StringBuilder();
    InputStream is = null;
    
    try {
      DiskFileItemFactory factory = new DiskFileItemFactory();
      factory.setSizeThreshold(THRESHOLD);
      
      ServletFileUpload upload = new ServletFileUpload(factory);
      upload.setFileSizeMax(MAXSIZE);
      upload.setHeaderEncoding("utf-8");
      
      List<FileItem> items = (List<FileItem>) upload.parseRequest(request);
      
      List<Topic> topics = TopicDAO.getTopics(sql, taskNameShort, null, -1);
      Map<String,Topic> topicMap = new HashMap<String,Topic>();
      for ( Topic t : topics ) {
        topicMap.put(t.getExternalId(), t);
      }
      Map<String,String> formParams = new HashMap<String,String>();
      for (FileItem item : items) {
        if (!item.isFormField()) {
          // out of memory may happen if everything goes into string 
          is = item.getInputStream();
        } else {
          formParams.put( item.getFieldName(), item.getString() );
        }
      }
      
      // cannot read is here?!
      String poolName = formParams.get("poolName");
      String poolType = formParams.get("poolType");
      
      //BAD: <?xml version=1.0 encoding=UTF-8 ?>
      //org.xml.sax.SAXParseException: The value following "version" in the XML declaration must be a quoted string.

      if (poolType.equalsIgnoreCase("ir_pool")) {
        setUpPoolsIR( sql, is, taskNameShort, poolName, report );
      } else {
        setUpPoolsQA( sql, is, taskNameShort, poolName, report );
      }
     
      report.append(UPLOAD_SUCCEEDED);
      Logger.log(sql, request.getSession(), "UPLOAD POOL", poolName);
    } catch (Exception e) {
      report.append(UPLOAD_SYSTEM_ERROR+"<br>"+ExceptionUtil.exceptionToString(e));
    } finally {
      if (is!=null ) {
        is.close();
      }
    }

    return report.toString();
  }
  
  private void setUpPoolsIR( SQL sql, InputStream is, String taskNameShort, 
          String poolName, StringBuilder report ) throws Exception {
    RetrievalResultSet rs = RunXmlFacade.deserializeRetrievalResultSet(is);
    IRJudgmentUnitDAO.storeUnits( sql, taskNameShort, poolName, rs );
    report.append("Finished loading pool for "+taskNameShort+" - "+poolName);
    report.append("<ul>");
    for (String key : rs.keySet()) {
      report.append("<li>"+key+"\t"+rs.get(key).size()+"<br></li>\n");
    }
    report.append("</ul>");
  }

  private void setUpPoolsQA( SQL sql, InputStream is, String taskNameShort, 
          String poolName, StringBuilder report ) throws Exception {
    SelectionResultSet rs = RunXmlFacade.deserializeSelectionResultSet(is);
    QAJudgmentUnitDAO.storeUnits( sql, taskNameShort, poolName, rs );
    System.out.println("Finished loading pool for "+taskNameShort+" - "+poolName);
    
    report.append("Finished loading pool for "+taskNameShort+" - "+poolName);
    report.append("<ul>");
    for (String key : rs.keySet()) {
      report.append("<li>"+key+"\t"+rs.get(key).size()+"<br></li>\n");
    }
    report.append("</ul>");
  }
  
}
